1 /**
2  * T-Tree.
3  * Copyright: © 2015 Economic Modeling Specialists, Intl.
4  * Authors: Brian Schott
5  * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
6  */
7 
8 module containers.ttree;
9 
10 private import containers.internal.node : shouldAddGCRange;
11 private import containers.internal.mixins : AllocatorState;
12 private import std.experimental.allocator.mallocator : Mallocator;
13 
14 /**
15  * Implements a binary search tree with multiple items per tree node.
16  *
17  * T-tree Nodes are (by default) sized to fit within a 64-byte
18  * cache line. The number of items stored per node can be read from the
19  * `nodeCapacity` enum. Each node has 0, 1, or 2 children. Each node has between
20  * 1 and `nodeCapacity` items, or it has `nodeCapacity` items and 0 or
21  * more children.
22  *
23  * Inserting or removing items while iterating a range returned from `opSlice`,
24  * `upperBound`, `equalRange`, or other similar functions will result in
25  * unpredicable and likely invalid iteration orders.
26  *
27  * Params:
28  *     T = the element type
29  *     Allocator = the allocator to use. Defaults to `Mallocator`.
30  *     allowDuplicates = if true, duplicate values will be allowed in the tree
31  *     less = the comparitor function to use
32  *     supportGC = true if the container should support holding references to
33  *         GC-allocated memory.
34  *     cacheLineSize = Nodes will be sized to fit within this number of bytes.
35  * See_also: $(LINK http://en.wikipedia.org/wiki/T-tree)
36  */
37 struct TTree(T, Allocator = Mallocator, bool allowDuplicates = false,
38 	alias less = "a < b", bool supportGC = shouldAddGCRange!T, size_t cacheLineSize = 64)
39 {
40 	/**
41 	 * T-Trees are not copyable due to the way they manage memory and interact
42 	 * with allocators.
43 	 */
44 	this(this) @disable;
45 
46 	static if (stateSize!Allocator != 0)
47 	{
48 		/// No default construction if an allocator must be provided.
49 		this() @disable;
50 
51 		/**
52 		 * Use `allocator` to allocate and free nodes in the tree.
53 		 */
54 		this(Allocator allocator)
55 		in
56 		{
57 			assert(allocator !is null, "Allocator must not be null");
58 		}
59 		do
60 		{
61 			this.allocator = allocator;
62 		}
63 
64 		private alias AllocatorType = Allocator;
65 	}
66 	else
67 		private alias AllocatorType = void*;
68 
69 	~this() @trusted
70 	{
71 		scope(failure) assert(false, "TTree destructor threw an exception");
72 		clear();
73 	}
74 
75 	/**
76 	 * Removes all elements from the tree.
77 	 */
78 	void clear()
79 	{
80 		_length = 0;
81 		if (root is null)
82 			return;
83 		static if (stateSize!Allocator > 0)
84 			deallocateNode(root, allocator);
85 		else
86 			deallocateNode(root, null);
87 	}
88 
89 	debug(EMSI_CONTAINERS) invariant()
90 	{
91 		assert (root is null || _length != 0, "Empty tree with non-null root");
92 	}
93 
94 	/**
95 	 * $(B tree ~= item) operator overload.
96 	 */
97 	void opOpAssign(string op)(T value) if (op == "~")
98 	{
99 		insert(value);
100 	}
101 
102 	/**
103 	 * Inserts the given value(s) into the tree.
104 	 *
105 	 * This is not a stable insert. You will get strange results if you insert
106 	 * into a tree while iterating over it.
107 	 *
108 	 * Params:
109 	 *     value = the value to insert
110 	 *     overwrite = if `true` the given `value` will replace the first item
111 	 *         in the tree that is equivalent (That is greater-than and less-than
112 	 *         are both false) to `value`. This is useful in cases where opCmp
113 	 *         and opEquals for `T` type have different meanings. For example,
114 	 *         if the element type is a circle that has a position and a color,
115 	 *         the circle could implement `opCmp` to sort by color, and calling
116 	 *         `insert` with `overwrite` set to `true` would allow you to update
117 	 *         the position of the circle with a certain color in the tree.
118 	 * Returns: the number of values added.
119 	 */
120 	size_t insert(T value, bool overwrite = false) @safe
121 	{
122 		if (root is null)
123 		{
124 			static if (stateSize!Allocator > 0)
125 				root = allocateNode(cast(Value) value, null, allocator);
126 			else
127 				root = allocateNode(cast(Value) value, null, null);
128 			++_length;
129 			return true;
130 		}
131 		static if (stateSize!Allocator > 0)
132 			immutable bool r = root.insert(cast(Value) value, root, allocator, overwrite);
133 		else
134 			immutable bool r = root.insert(cast(Value) value, root, null, overwrite);
135 		if (r)
136 			++_length;
137 		return r ? 1 : 0;
138 	}
139 
140 	/// ditto
141 	size_t insert(R)(R r, bool overwrite = false) if (isInputRange!R && is(ElementType!R == T))
142 	{
143 		size_t retVal;
144 		while (!r.empty)
145 		{
146 			retVal += insert(r.front(), overwrite);
147 			r.popFront();
148 		}
149 		return retVal;
150 	}
151 
152 	/// ditto
153 	size_t insert(T[] values, bool overwrite = false)
154 	{
155 		size_t retVal;
156 		foreach (ref v; values)
157 			retVal += insert(v, overwrite);
158 		return retVal;
159 	}
160 
161 	/// ditto
162 	alias insertAnywhere = insert;
163 
164 	/// ditto
165 	alias put = insert;
166 
167 	/**
168 	 * Removes a single value from the tree, or does nothing.
169 	 *
170 	 * If `allowDuplicates` is true only a single element that is equivalent to
171 	 * the given `value` will be removed. Which of these elements is removed is
172 	 * not defined.
173 	 *
174 	 * Params:
175 	 *     value = a value equal to the one to be removed
176 	 *     cleanup = a function that should be run on the removed item
177 	 * Retuns: true if any value was removed
178 	 */
179 	bool remove(T value, void delegate(T) cleanup = null)
180 	{
181 		static if (stateSize!Allocator > 0)
182 			immutable bool removed = root !is null && root.remove(cast(Value) value, root, allocator, cleanup);
183 		else
184 			immutable bool removed = root !is null && root.remove(cast(Value) value, root, null, cleanup);
185 		if (removed)
186 		{
187 			--_length;
188 			if (_length == 0)
189 			{
190 				static if (stateSize!Allocator > 0)
191 					deallocateNode(root, allocator);
192 				else
193 					deallocateNode(root, null);
194 			}
195 		}
196 		return removed;
197 	}
198 
199 	/**
200 	 * Returns: true if the tree _conains the given value
201 	 */
202 	bool contains(T value) const @nogc @safe
203 	{
204 		return root !is null && root.contains(value);
205 	}
206 
207 	/**
208 	 * Returns: the number of elements in the tree.
209 	 */
210 	size_t length() const pure nothrow @nogc @safe @property
211 	{
212 		return _length;
213 	}
214 
215 	/**
216 	 * Returns: true if the tree is empty.
217 	 */
218 	bool empty() const pure nothrow @nogc @safe @property
219 	{
220 		return _length == 0;
221 	}
222 
223 	/**
224 	 * Returns: a range over the tree. Do not insert into the tree while
225 	 *     iterating because you may iterate over the same value multiple times
226 	 *     or skip some values entirely.
227 	 */
228 	auto opSlice(this This)() inout @trusted @nogc
229 	{
230 		return Range!(This)(cast(const(Node)*) root, RangeType.all, T.init);
231 	}
232 
233 	/**
234 	 * Returns: a range of elements which are less than value.
235 	 */
236 	auto lowerBound(this This)(inout T value) inout @trusted
237 	{
238 		return Range!(This)(cast(const(Node)*) root, RangeType.lower, value);
239 	}
240 
241 	/**
242 	 * Returns: a range of elements which are equivalent (though not necessarily
243 	 *     equal) to value.
244 	 */
245 	auto equalRange(this This)(inout T value) inout @trusted
246 	{
247 		return Range!(This)(cast(const(Node)*) root, RangeType.equal, value);
248 	}
249 
250 	/**
251 	 * Returns: a range of elements which are greater than value.
252 	 */
253 	auto upperBound(this This)(inout T value) inout @trusted
254 	{
255 		return Range!(This)(cast(const(Node)*) root, RangeType.upper, value);
256 	}
257 
258 	/**
259 	 * Returns: the first element in the tree.
260 	 */
261 	auto front(this This)() inout pure @trusted @property
262 	{
263 		import std.exception : enforce;
264 
265 		alias CET = ContainerElementType!(This, T);
266 		enforce(!empty(), "Attepted to get the front of an empty tree.");
267 		Node* current = cast(Node*) root;
268 		while (current.left !is null)
269 			current = current.left;
270 		return cast(CET) current.values[0];
271 	}
272 
273 	/**
274 	 * Returns: the last element in the tree.
275 	 */
276 	auto back(this This)() inout pure @trusted @property
277 	{
278 		import std.exception : enforce;
279 
280 		alias CET = ContainerElementType!(This, T);
281 		enforce(!empty(), "Attepted to get the back of an empty tree.");
282 		Node* current = cast(Node*) root;
283 		while (current.right !is null)
284 			current = current.right;
285 		return cast(CET) current.values[current.nextAvailableIndex - 1];
286 	}
287 
288 	/**
289 	 * Tree range
290 	 */
291 	static struct Range(ThisT)
292 	{
293 		@disable this();
294 
295 		/**
296 		 * Standard range operations
297 		 */
298 		ET front() const @property @nogc
299 		{
300 			return cast(typeof(return)) current.values[index];
301 		}
302 
303 		/// ditto
304 		bool empty() const pure nothrow @nogc @safe @property
305 		{
306 			return current is null;
307 		}
308 
309 		/// ditto
310 		void popFront()
311 		{
312 			_popFront();
313 			if (current is null)
314 				return;
315 			with (RangeType) final switch (type)
316 			{
317 			case upper:
318 			case all: break;
319 			case equal:
320 				if (_less(val, front()))
321 					current = null;
322 				break;
323 			case lower:
324 				if (!_less(front(), val))
325 					current = null;
326 				break;
327 			}
328 		}
329 
330 	package(containers):
331 
332 		// The TreeMap container needs to be able to modify part of the tree
333 		// in-place. The reason that this works is that the value part of the
334 		// key-value struct contained in a TTree used by a TreeMap is not used
335 		// when comparing nodes. Normal users of the containers library cannot
336 		// get a reference to the elements because modifying them will violate
337 		// the ordering invariant of the tree.
338 		T* _containersFront() const @property @nogc @trusted
339 		{
340 			return cast(T*) &current.values[index];
341 		}
342 
343 	private:
344 
345 		alias ET = ContainerElementType!(ThisT, T);
346 
347 		void currentToLeftmost() @nogc
348 		{
349 			if (current is null)
350 				return;
351 			while (current.left !is null)
352 				current = current.left;
353 		}
354 
355 		void currentToLeastContaining(inout T val)
356 		{
357 			if (current is null)
358 				return;
359 			while (current !is null)
360 			{
361 				assert(current.registry != 0, "Empty node");
362 				auto first = current.values[0];
363 				auto last = current.values[current.nextAvailableIndex - 1];
364 				immutable bool valLessFirst = _less(val, first);
365 				immutable bool valLessLast = _less(val, last);
366 				immutable bool firstLessVal = _less(first, val);
367 				immutable bool lastLessVal = _less(last, val);
368 				if (firstLessVal && valLessLast)
369 					return;
370 				else if (valLessFirst)
371 					current = current.left;
372 				else if (lastLessVal)
373 					current = current.right;
374 				else
375 				{
376 					static if (allowDuplicates)
377 					{
378 						if (!valLessFirst && !firstLessVal)
379 						{
380 							auto c = current;
381 							current = current.left;
382 							currentToLeastContaining(val);
383 							if (current is null)
384 								current = c;
385 							return;
386 						}
387 						else
388 							return;
389 					}
390 					else
391 						return;
392 				}
393 
394 			}
395 		}
396 
397 		this(inout(Node)* n, RangeType type, inout T val) @nogc
398 		{
399 			current = n;
400 			this.type = type;
401 			this.val = val;
402 			with (RangeType) final switch(type)
403 			{
404 			case all:
405 				currentToLeftmost();
406 				break;
407 			case lower:
408 				currentToLeftmost();
409 				if (_less(val, front()))
410 					current = null;
411 				break;
412 			case equal:
413 				currentToLeastContaining(val);
414 				while (current !is null && _less(front(), val))
415 					_popFront();
416 				if (current is null || _less(front(), val) || _less(val, front()))
417 					current = null;
418 				break;
419 			case upper:
420 				currentToLeastContaining(val);
421 				while (current !is null && !_less(val, front()))
422 					_popFront();
423 				break;
424 			}
425 		}
426 
427 		void _popFront() @nogc
428 		in
429 		{
430 			assert (!empty, "Calling .popFront with empty TTree");
431 		}
432 		do
433 		{
434 			index++;
435 			if (index >= nodeCapacity || current.isFree(index))
436 			{
437 				index = 0;
438 				if (current.right !is null)
439 				{
440 					current = current.right;
441 					while (current.left !is null)
442 						current = current.left;
443 				}
444 				else if (current.parent is null)
445 					current = null;
446 				else if (current.parent.left is current)
447 					current = current.parent;
448 				else
449 				{
450 					while (current.parent.right is current)
451 					{
452 						current = current.parent;
453 						if (current.parent is null)
454 						{
455 							current = null;
456 							return;
457 						}
458 					}
459 					current = current.parent;
460 				}
461 			}
462 		}
463 
464 		size_t index;
465 		const(Node)* current;
466 		const RangeType type;
467 		const T val;
468 	}
469 
470 	mixin AllocatorState!Allocator;
471 
472 	/// The number of values that can be stored in a single T-Tree node.
473 	enum size_t nodeCapacity = N[0];
474 
475 private:
476 
477 	import containers.internal.element_type : ContainerElementType;
478 	import containers.internal.node : FatNodeInfo, fullBits, shouldAddGCRange, shouldNullSlot;
479 	import containers.internal.storage_type : ContainerStorageType;
480 	import std.algorithm : sort;
481 	import std.functional: binaryFun;
482 	import std.range : ElementType, isInputRange;
483 	import std.traits: isPointer, PointerTarget;
484 	import std.experimental.allocator.common : stateSize;
485 
486 	alias N = FatNodeInfo!(T.sizeof, 3, cacheLineSize, ulong.sizeof);
487 	alias Value = ContainerStorageType!T;
488 	alias BookkeepingType = N[1];
489 	enum HEIGHT_BIT_OFFSET = 48UL;
490 	enum fullBitPattern = fullBits!(ulong, nodeCapacity);
491 	enum RangeType : ubyte { all, lower, equal, upper }
492 	enum bool useGC = supportGC && shouldAddGCRange!T;
493 
494 	static assert (nodeCapacity <= HEIGHT_BIT_OFFSET, "cannot fit height info and registry in ulong");
495 	static assert (nodeCapacity <= (typeof(Node.registry).sizeof * 8));
496 	static assert (Node.sizeof <= cacheLineSize);
497 
498 	// If we're storing a struct that defines opCmp, don't compare pointers as
499 	// that is almost certainly not what the user intended.
500 	static if (is(typeof(less) == string ))
501 	{
502 		// Everything inside of this `static if` is dumb. `binaryFun` does not
503 		// correctly infer nothrow and @nogc attributes, among other things, so
504 		// we need to declare a function here that has its attributes properly
505 		// inferred. It's not currently possible, however, to use this function
506 		// with std.algorithm.sort because of symbol visibility issues. Because
507 		// of this problem, keep a duplicate of the sorting predicate in string
508 		// form in the `_lessStr` alias.
509 		static if (less == "a < b" && isPointer!T
510 				&& __traits(hasMember, PointerTarget!T, "opCmp"))
511 		{
512 			enum _lessStr = "a.opCmp(*b) < 0";
513 			static bool _less(TT)(const TT a, const TT b)
514 			{
515 				return a.opCmp(*b) < 0;
516 			}
517 		}
518 		else
519 		{
520 			enum _lessStr = less;
521 			alias _less = binaryFun!less;
522 		}
523 	}
524 	else
525 		alias _less = binaryFun!less;
526 
527 	static Node* allocateNode(Value value, Node* parent, AllocatorType allocator) @trusted
528 	out (result)
529 	{
530 		assert (result.left is null);
531 		assert (result.right is null);
532 	}
533 	do
534 	{
535 		import core.memory : GC;
536 		import std.experimental.allocator : make;
537 
538 		static if (stateSize!Allocator == 0)
539 			Node* n = make!Node(Allocator.instance);
540 		else
541 			Node* n = make!Node(allocator);
542 		n.parent = parent;
543 		n.markUsed(0);
544 		n.values[0] = cast(Value) value;
545 		static if (useGC)
546 			GC.addRange(n, Node.sizeof);
547 		return n;
548 	}
549 
550 	static void deallocateNode(ref Node* n, AllocatorType allocator)
551 	in
552 	{
553 		assert (n !is null);
554 	}
555 	do
556 	{
557 		import std.experimental.allocator : dispose;
558 		import core.memory : GC;
559 
560 		if (n.left !is null)
561 			deallocateNode(n.left, allocator);
562 		if (n.right !is null)
563 			deallocateNode(n.right, allocator);
564 
565 		static if (useGC)
566 			GC.removeRange(n);
567 		static if (stateSize!Allocator == 0)
568 			dispose(Allocator.instance, n);
569 		else
570 			dispose(allocator, n);
571 		n = null;
572 	}
573 
574 	static struct Node
575 	{
576 		private size_t nextAvailableIndex() const pure nothrow @nogc @safe
577 		{
578 			import containers.internal.backwards : bsf;
579 
580 			return bsf(~(registry & fullBitPattern));
581 		}
582 
583 		private void markUsed(size_t index) pure nothrow @nogc @safe
584 		{
585 			registry |= (1UL << index);
586 		}
587 
588 		private void markUnused(size_t index) pure nothrow @nogc @safe
589 		{
590 			registry &= ~(1UL << index);
591 			static if (shouldNullSlot!T)
592 				values[index] = null;
593 		}
594 
595 		private bool isFree(size_t index) const pure nothrow @nogc @safe
596 		{
597 			return (registry & (1UL << index)) == 0;
598 		}
599 
600 		private bool isFull() const pure nothrow @nogc @safe
601 		{
602 			return (registry & fullBitPattern) == fullBitPattern;
603 		}
604 
605 		private bool isEmpty() const pure nothrow @nogc @safe
606 		{
607 			return (registry & fullBitPattern) == 0;
608 		}
609 
610 		bool contains(Value value) const @trusted
611 		{
612 			import std.range : assumeSorted;
613 			size_t i = nextAvailableIndex();
614 			if (_less(value, cast(Value) values[0]))
615 				return left !is null && left.contains(value);
616 			if (_less(values[i - 1], value))
617 				return right !is null && right.contains(value);
618 			static if (is(typeof(_lessStr)))
619 				return !assumeSorted!_lessStr(values[0 .. i]).equalRange(value).empty;
620 			else
621 				return !assumeSorted!_less(values[0 .. i]).equalRange(value).empty;
622 		}
623 
624 		ulong calcHeight() pure nothrow @nogc @safe
625 		{
626 			immutable ulong l = left !is null ? left.height() : 0;
627 			immutable ulong r = right !is null ? right.height() : 0;
628 			immutable ulong h = 1 + (l > r ? l : r);
629 			assert (h < ushort.max, "Height overflow");
630 			registry &= fullBitPattern;
631 			registry |= (h << HEIGHT_BIT_OFFSET);
632 			return h;
633 		}
634 
635 		ulong height() const pure nothrow @nogc @safe
636 		{
637 			return registry >>> HEIGHT_BIT_OFFSET;
638 		}
639 
640 		int imbalanced() const pure nothrow @nogc @safe
641 		{
642 			if (right !is null
643 					&& ((left is null && right.height() > 1)
644 					|| (left !is null && right.height() > left.height() + 1)))
645 				return 1;
646 			if (left !is null
647 					&& ((right is null && left.height() > 1)
648 					|| (right !is null && left.height() > right.height() + 1)))
649 				return -1;
650 			return 0;
651 		}
652 
653 		bool insert(T value, ref Node* root, AllocatorType allocator, bool overwrite) @trusted
654 		in
655 		{
656 			static if (isPointer!T || is (T == class) || is (T == interface))
657 				assert (value !is null, "Inserting null values is not allowed");
658 		}
659 		do
660 		{
661 			import std.algorithm : sort;
662 			import std.range : assumeSorted;
663 			if (!isFull())
664 			{
665 				immutable size_t index = nextAvailableIndex();
666 				static if (!allowDuplicates)
667 				{
668 					static if (is(typeof(_lessStr)))
669 						auto r = assumeSorted!_lessStr(values[0 .. index]).trisect(
670 							cast(Value) value);
671 					else
672 						auto r = assumeSorted!_less(values[0 .. index]).trisect(
673 							cast(Value) value);
674 					if (!r[1].empty)
675 					{
676 						if (overwrite)
677 						{
678 							values[r[0].length] = cast(Value) value;
679 							return true;
680 						}
681 						return false;
682 					}
683 				}
684 				values[index] = cast(Value) value;
685 				markUsed(index);
686 				static if (is(typeof(_lessStr)))
687 					sort!_lessStr(values[0 .. index + 1]);
688 				else
689 					sort!_less(values[0 .. index + 1]);
690 				return true;
691 			}
692 			if (_less(value, values[0]))
693 			{
694 				if (left is null)
695 				{
696 					left = allocateNode(cast(Value) value, &this, allocator);
697 					calcHeight();
698 					return true;
699 				}
700 				immutable bool b = left.insert(value, root, allocator, overwrite);
701 				if (imbalanced() == -1)
702 					rotateRight(root, allocator);
703 				calcHeight();
704 				return b;
705 			}
706 			if (_less(values[$ - 1], cast(Value) value))
707 			{
708 				if (right is null)
709 				{
710 					right = allocateNode(value, &this, allocator);
711 					calcHeight();
712 					return true;
713 				}
714 				immutable bool b = right.insert(value, root, allocator, overwrite);
715 				if (imbalanced() == 1)
716 					rotateLeft(root, allocator);
717 				calcHeight();
718 				return b;
719 			}
720 			static if (!allowDuplicates)
721 			{
722 				static if (is(typeof(_lessStr)))
723 				{
724 					if (!assumeSorted!_lessStr(values[]).equalRange(cast(Value) value).empty)
725 						return false;
726 				}
727 				else
728 				{
729 					if (!assumeSorted!_less(values[]).equalRange(cast(Value) value).empty)
730 						return false;
731 				}
732 			}
733 
734 			Value[nodeCapacity + 1] temp = void;
735 			temp[0 .. $ - 1] = values[];
736 			temp[$ - 1] = cast(Value) value;
737 			static if (is(typeof(_lessStr)))
738 				sort!_lessStr(temp[]);
739 			else
740 				sort!_less(temp[]);
741 			if (right is null)
742 			{
743 				values[] = temp[0 .. $ - 1];
744 				right = allocateNode(temp[$ - 1], &this, allocator);
745 				return true;
746 			}
747 			if (left is null)
748 			{
749 				values[] = temp[1 .. $];
750 				left = allocateNode(temp[0], &this, allocator);
751 				return true;
752 			}
753 			if (right.height < left.height)
754 			{
755 				values[] = temp[0 .. $ - 1];
756 				immutable bool b = right.insert(temp[$ - 1], root, allocator, overwrite);
757 				if (imbalanced() == 1)
758 					rotateLeft(root, allocator);
759 				calcHeight();
760 				return b;
761 			}
762 			values[] = temp[1 .. $];
763 			immutable bool b = left.insert(temp[0], root, allocator, overwrite);
764 			if (imbalanced() == -1)
765 				rotateRight(root, allocator);
766 			calcHeight();
767 			return b;
768 		}
769 
770 		bool remove(Value value, ref Node* n, AllocatorType allocator,
771 			void delegate(T) cleanup = null)
772 		{
773 			import std.range : assumeSorted;
774 			assert (!isEmpty(), "Calling .remove on an empty TTree.Node");
775 			if (isFull() && _less(value, values[0]))
776 			{
777 				immutable bool r = left !is null && left.remove(value, left, allocator, cleanup);
778 				if (left.isEmpty())
779 					deallocateNode(left, allocator);
780 				return r;
781 			}
782 			if (isFull() && _less(values[$ - 1], value))
783 			{
784 				immutable bool r = right !is null && right.remove(value, right, allocator, cleanup);
785 				if (right.isEmpty())
786 					deallocateNode(right, allocator);
787 				return r;
788 			}
789 			size_t i = nextAvailableIndex();
790 			static if (is(typeof(_lessStr)))
791 				auto sv = assumeSorted!_lessStr(values[0 .. i]);
792 			else
793 				auto sv = assumeSorted!_less(values[0 .. i]);
794 			auto tri = sv.trisect(value);
795 			if (tri[1].length == 0)
796 				return false;
797 			// Clean up removed item
798 			if (cleanup !is null)
799 				cleanup(tri[1][0]);
800 			immutable size_t l = tri[0].length;
801 			if (right is null && left is null)
802 			{
803 				Value[nodeCapacity - 1] temp;
804 				temp[0 .. l] = values[0 .. l];
805 				temp[l .. $] = values[l + 1 .. $];
806 				values[0 .. $ - 1] = temp[];
807 				markUnused(nextAvailableIndex() - 1);
808 			}
809 			else if (right !is null)
810 			{
811 				Value[nodeCapacity - 1] temp;
812 				temp[0 .. l] = values[0 .. l];
813 				temp[l .. $] = values[l + 1 .. $];
814 				values[0 .. $ - 1] = temp[];
815 				values[$ - 1] = right.removeSmallest(allocator);
816 				if (right.isEmpty())
817 					deallocateNode(right, allocator);
818 			}
819 			else if (left !is null)
820 			{
821 				Value[nodeCapacity - 1] temp;
822 				temp[0 .. l] = values[0 .. l];
823 				temp[l .. $] = values[l + 1 .. $];
824 				values[1 .. $] = temp[];
825 				values[0] = left.removeLargest(allocator);
826 				if (left.isEmpty())
827 					deallocateNode(left, allocator);
828 			}
829 			return true;
830 		}
831 
832 		Value removeSmallest(AllocatorType allocator)
833 		in
834 		{
835 			assert (!isEmpty(), "Calling .removeSmallest on an empty TTree.Node");
836 		}
837 		do
838 		{
839 			if (left is null && right is null)
840 			{
841 				Value r = values[0];
842 				Value[nodeCapacity - 1] temp = void;
843 				temp[] = values[1 .. $];
844 				values[0 .. $ - 1] = temp[];
845 				markUnused(nextAvailableIndex() - 1);
846 				return r;
847 			}
848 			if (left !is null)
849 			{
850 				auto r = left.removeSmallest(allocator);
851 				if (left.isEmpty())
852 					deallocateNode(left, allocator);
853 				return r;
854 			}
855 			Value r = values[0];
856 			Value[nodeCapacity - 1] temp = void;
857 			temp[] = values[1 .. $];
858 			values[0 .. $ - 1] = temp[];
859 			values[$ - 1] = right.removeSmallest(allocator);
860 			if (right.isEmpty())
861 				deallocateNode(right, allocator);
862 			return r;
863 		}
864 
865 		Value removeLargest(AllocatorType allocator)
866 		in
867 		{
868 			assert (!isEmpty(), "Calling .removeLargest on an empty TTree.Node");
869 		}
870 		out (result)
871 		{
872 			static if (isPointer!T || is (T == class) || is(T == interface))
873 				assert (result !is null, "Removed a null value");
874 		}
875 		do
876 		{
877 			if (left is null && right is null)
878 			{
879 				immutable size_t i = nextAvailableIndex() - 1;
880 				Value r = values[i];
881 				markUnused(i);
882 				return r;
883 			}
884 			if (right !is null)
885 			{
886 				auto r = right.removeLargest(allocator);
887 				if (right.isEmpty())
888 					deallocateNode(right, allocator);
889 				return r;
890 			}
891 			Value r = values[$ - 1];
892 			Value[nodeCapacity - 1] temp = void;
893 			temp[] = values[0 .. $ - 1];
894 			values[1 .. $] = temp[];
895 			values[0] = left.removeLargest(allocator);
896 			if (left.isEmpty())
897 				deallocateNode(left, allocator);
898 			return r;
899 		}
900 
901 		void rotateLeft(ref Node* root, AllocatorType allocator) @safe
902 		{
903 			Node* newRoot;
904 			if (right.left !is null && right.right is null)
905 			{
906 				newRoot = right.left;
907 				newRoot.parent = this.parent;
908 				newRoot.left = &this;
909 				newRoot.left.parent = newRoot;
910 				newRoot.right = right;
911 				newRoot.right.parent = newRoot;
912 				newRoot.right.left = null;
913 				right = null;
914 				left = null;
915 			}
916 			else
917 			{
918 				newRoot = right;
919 				newRoot.parent = this.parent;
920 				right = newRoot.left;
921 				if (right !is null)
922 					right.parent = &this;
923 				newRoot.left = &this;
924 				this.parent = newRoot;
925 			}
926 			cleanup(newRoot, root, allocator);
927 		}
928 
929 		void rotateRight(ref Node* root, AllocatorType allocator) @safe
930 		{
931 			Node* newRoot;
932 			if (left.right !is null && left.left is null)
933 			{
934 				newRoot = left.right;
935 				newRoot.parent = this.parent;
936 				newRoot.right = &this;
937 				newRoot.right.parent = newRoot;
938 				newRoot.left = left;
939 				newRoot.left.parent = newRoot;
940 				newRoot.left.right = null;
941 				left = null;
942 				right = null;
943 			}
944 			else
945 			{
946 				newRoot = left;
947 				newRoot.parent = this.parent;
948 				left = newRoot.right;
949 				if (left !is null)
950 					left.parent = &this;
951 				newRoot.right = &this;
952 				this.parent = newRoot;
953 			}
954 			cleanup(newRoot, root, allocator);
955 		}
956 
957 		void cleanup(Node* newRoot, ref Node* root, AllocatorType allocator) @safe
958 		{
959 			if (newRoot.parent !is null)
960 			{
961 				if (newRoot.parent.right is &this)
962 					newRoot.parent.right = newRoot;
963 				else
964 					newRoot.parent.left = newRoot;
965 			}
966 			else
967 				root = newRoot;
968 			newRoot.fillFromChildren(root, allocator);
969 			if (newRoot.left !is null)
970 			{
971 				newRoot.left.fillFromChildren(root, allocator);
972 			}
973 			if (newRoot.right !is null)
974 			{
975 				newRoot.right.fillFromChildren(root, allocator);
976 			}
977 			if (newRoot.left !is null)
978 				newRoot.left.calcHeight();
979 			if (newRoot.right !is null)
980 				newRoot.right.calcHeight();
981 			newRoot.calcHeight();
982 		}
983 
984 		void fillFromChildren(ref Node* root, AllocatorType allocator) @trusted
985 		{
986 			while (!isFull())
987 			{
988 				if (left !is null)
989 				{
990 					insert(left.removeLargest(allocator), root, allocator, false);
991 					if (left.isEmpty())
992 						deallocateNode(left, allocator);
993 				}
994 				else if (right !is null)
995 				{
996 					insert(right.removeSmallest(allocator), root, allocator, false);
997 					if (right.isEmpty())
998 						deallocateNode(right, allocator);
999 				}
1000 				else
1001 					return;
1002 			}
1003 		}
1004 
1005 		debug(EMSI_CONTAINERS) invariant()
1006 		{
1007 			import std..string : format;
1008 			assert (&this !is null, "Null this");
1009 			assert (left !is &this, "%x, %x".format(left, &this));
1010 			assert (right !is &this, "%x, %x".format(right, &this));
1011 			if (left !is null)
1012 			{
1013 				assert (left.left !is &this, "%s".format(values));
1014 				assert (left.right !is &this, "%x, %x".format(left.right, &this));
1015 				assert (left.parent is &this, "%x, %x, %x".format(left, left.parent, &this));
1016 			}
1017 			if (right !is null)
1018 			{
1019 				assert (right.left !is &this, "%s".format(values));
1020 				assert (right.right !is &this, "%s".format(values));
1021 				assert (right.parent is &this, "%x, %x, %x".format(right, right.parent, &this));
1022 			}
1023 		}
1024 
1025 		Value[nodeCapacity] values;
1026 		Node* left;
1027 		Node* right;
1028 		Node* parent;
1029 		ulong registry = 1UL << HEIGHT_BIT_OFFSET;
1030 	}
1031 
1032 	size_t _length;
1033 	Node* root;
1034 }
1035 
1036 version(emsi_containers_unittest) unittest
1037 {
1038 	import core.memory : GC;
1039 	import std.algorithm : equal, sort, map, filter, each;
1040 	import std.array : array;
1041 	import std.range : iota, walkLength, isInputRange;
1042 	import std..string : format;
1043 	import std.uuid : randomUUID;
1044 
1045 	{
1046 		TTree!int kt;
1047 		assert (kt.empty);
1048 		foreach (i; 0 .. 200)
1049 			assert (kt.insert(i));
1050 		assert(kt.front == 0);
1051 		assert(kt.back == 199);
1052 		assert(!kt.empty);
1053 		assert(kt.length == 200);
1054 		assert(kt.contains(30));
1055 	}
1056 
1057 	{
1058 		TTree!int kt;
1059 		assert (!kt.contains(5));
1060 		kt.insert(2_000);
1061 		assert (kt.contains(2_000));
1062 		foreach_reverse (i; 0 .. 1_000)
1063 		{
1064 			assert (kt.insert(i));
1065 		}
1066 		assert (!kt.contains(100_000));
1067 	}
1068 
1069 	{
1070 		import std.random : uniform;
1071 		TTree!int kt;
1072 		foreach (i; 0 .. 1_000)
1073 			kt.insert(uniform(0, 100_000));
1074 	}
1075 
1076 	{
1077 		TTree!int kt;
1078 		kt.insert(10);
1079 		assert (kt.length == 1);
1080 		assert (!kt.insert(10));
1081 		assert (kt.length == 1);
1082 	}
1083 
1084 	{
1085 		TTree!(int, Mallocator, true) kt;
1086 		assert (kt.insert(1));
1087 		assert (kt.length == 1);
1088 		assert (kt.insert(1));
1089 		assert (kt.length == 2);
1090 		assert (kt.contains(1));
1091 	}
1092 
1093 	{
1094 		TTree!(int) kt;
1095 		foreach (i; 0 .. 200)
1096 			assert (kt.insert(i));
1097 		assert (kt.length == 200);
1098 		assert (kt.remove(79));
1099 		assert (!kt.remove(79));
1100 		assert (kt.length == 199);
1101 	}
1102 
1103 	{
1104 		string[] strs = [
1105 			"2c381d2a-bacd-40db-b6d8-055b144c5ee6",
1106 			"62104b50-e235-4c95-bcb9-a545e88e2d09",
1107 			"828c8fc0-a392-4738-a49c-62e991fce090",
1108 			"62e30465-79eb-446e-b34f-af5d7c491486",
1109 			"93ec245b-60d2-4422-91ff-66a6d7e299fc",
1110 			"c1d2f3d7-82cc-4d90-a2c5-9fba335f36cd",
1111 			"c9d8d980-94eb-4941-b873-00d68021522f",
1112 			"82dbc4df-cb3c-447a-9d73-cd6291a0ba02",
1113 			"8d259231-6ab6-49e4-9bb6-fe097c4153ed",
1114 			"f9f2d719-61e1-4f62-ae2c-bf2a24a13d5b"
1115 		];
1116 		TTree!string strings;
1117 		foreach (i, s; strs)
1118 			assert (strings.insert(s));
1119 		sort(strs[]);
1120 		assert (equal(strs, strings[]));
1121 	}
1122 
1123 	foreach (x; 0 .. 1000)
1124 	{
1125 		TTree!string strings;
1126 		string[] strs = iota(10).map!(a => randomUUID().toString()).array();
1127 		foreach (i, s; strs)
1128 			assert (strings.insert(s));
1129 		assert (strings.length == strs.length);
1130 		sort(strs);
1131 		assert (equal(strs, strings[]));
1132 	}
1133 
1134 	{
1135 		TTree!string strings;
1136 		strings.insert(["e", "f", "a", "b", "c", "d"]);
1137 		assert (equal(strings[], ["a", "b", "c", "d", "e", "f"]));
1138 	}
1139 
1140 	{
1141 		TTree!(string, Mallocator, true) strings;
1142 		assert (strings.insert("b"));
1143 		assert (strings.insert("c"));
1144 		assert (strings.insert("a"));
1145 		assert (strings.insert("d"));
1146 		assert (strings.insert("d"));
1147 		assert (strings.length == 5);
1148 		assert (equal(strings.equalRange("d"), ["d", "d"]), format("%s", strings.equalRange("d")));
1149 		assert (equal(strings.equalRange("a"), ["a"]), format("%s", strings.equalRange("a")));
1150 		assert (equal(strings.lowerBound("d"), ["a", "b", "c"]), format("%s", strings.lowerBound("d")));
1151 		assert (equal(strings.upperBound("c"), ["d", "d"]), format("%s", strings.upperBound("c")));
1152 	}
1153 
1154 	{
1155 		static struct S
1156 		{
1157 			string x;
1158 			int opCmp (ref const S other) const @nogc
1159 			{
1160 				if (x < other.x)
1161 					return -1;
1162 				if (x > other.x)
1163 					return 1;
1164 				return 0;
1165 			}
1166 		}
1167 
1168 		TTree!(S*, Mallocator, true) stringTree;
1169 		auto one = S("offset");
1170 		stringTree.insert(&one);
1171 		auto two = S("object");
1172 		assert (stringTree.equalRange(&two).empty);
1173 		assert (!stringTree.equalRange(&one).empty);
1174 		assert (stringTree[].front.x == "offset");
1175 	}
1176 
1177 	{
1178 		static struct TestStruct
1179 		{
1180 			int opCmp(ref const TestStruct other) const @nogc
1181 			{
1182 				return x < other.x ? -1 : (x > other.x ? 1 : 0);
1183 			}
1184 			int x;
1185 			int y;
1186 		}
1187 		TTree!(TestStruct*) tsTree;
1188 		static assert (isInputRange!(typeof(tsTree[])));
1189 		foreach (i; 0 .. 100)
1190 			assert(tsTree.insert(new TestStruct(i, i * 2)));
1191 		assert (tsTree.length == 100);
1192 		auto r = tsTree[];
1193 		TestStruct* prev = r.front();
1194 		r.popFront();
1195 		while (!r.empty)
1196 		{
1197 			assert (r.front.x > prev.x, format("%s %s", prev.x, r.front.x));
1198 			prev = r.front;
1199 			r.popFront();
1200 		}
1201 		TestStruct a = TestStruct(30, 100);
1202 		auto eqArray = array(tsTree.equalRange(&a));
1203 		assert (eqArray.length == 1, format("%d", eqArray.length));
1204 	}
1205 
1206 	{
1207 		import std.algorithm : canFind;
1208 		TTree!int ints;
1209 		foreach (i; 0 .. 50)
1210 			ints ~= i;
1211 		assert (canFind(ints[], 20));
1212 		assert (walkLength(ints[]) == 50);
1213 		assert (walkLength(filter!(a => (a & 1) == 0)(ints[])) == 25);
1214 	}
1215 
1216 	{
1217 		TTree!int ints;
1218 		foreach (i; 0 .. 50)
1219 			ints ~=  i;
1220 		ints.remove(0);
1221 		assert (ints.length == 49);
1222 		foreach (i; 1 .. 12)
1223 			ints.remove(i);
1224 		assert (ints.length == 49 - 11);
1225 	}
1226 
1227 	{
1228 		const(TTree!(const(int))) getInts()
1229 		{
1230 			TTree!(const(int)) t;
1231 			t.insert(1);
1232 			t.insert(2);
1233 			t.insert(3);
1234 			return t;
1235 		}
1236 		auto t = getInts();
1237 		static assert (is (typeof(t[].front) == const(int)));
1238 		assert (equal(t[].filter!(a => a & 1), [1, 3]));
1239 	}
1240 
1241 
1242 	{
1243 		static struct ABC
1244 		{
1245 			ulong a;
1246 			ulong b;
1247 
1248 			int opCmp(ref const ABC other) const @nogc
1249 			{
1250 				if (this.a < other.a)
1251 					return -1;
1252 				if (this.a > other.a)
1253 					return 1;
1254 				return 0;
1255 			}
1256 		}
1257 
1258 		TTree!(ABC, Mallocator, true) tree;
1259 		foreach (i; 0 .. 10)
1260 			tree.insert(ABC(i));
1261 		tree.insert(ABC(15));
1262 		tree.insert(ABC(15));
1263 		tree.insert(ABC(15));
1264 		tree.insert(ABC(15));
1265 		foreach (i; 20 .. 30)
1266 			tree.insert(ABC(i));
1267 		assert(tree.equalRange(ABC(15)).walkLength() == 4,
1268 			format("Actual length = %d", tree.equalRange(ABC(15)).walkLength()));
1269 	}
1270 
1271 	{
1272 		TTree!int ints2;
1273 		iota(0, 1_000_000).each!(a => ints2.insert(a));
1274 		assert(equal(iota(0, 1_000_000), ints2[]));
1275 		assert(ints2.length == 1_000_000);
1276 		foreach (i; 0 .. 1_000_000)
1277 			assert(!ints2.equalRange(i).empty, format("Could not find %d", i));
1278 	}
1279 
1280 	{
1281 		TTree!int ints3;
1282 		foreach (i; iota(0, 1_000_000).filter!(a => a % 2 == 0))
1283 			ints3.insert(i);
1284 		assert(ints3.length == 500_000);
1285 		foreach (i; iota(0, 1_000_000).filter!(a => a % 2 == 0))
1286 			assert(!ints3.equalRange(i).empty);
1287 		foreach (i; iota(0, 1_000_000).filter!(a => a % 2 == 1))
1288 			assert(ints3.equalRange(i).empty);
1289 	}
1290 
1291 	{
1292 		TTree!(ubyte, Mallocator, true) ubytes;
1293 		foreach (i; iota(0, 1_000_000).filter!(a => a % 2 == 0).map!(a => cast(ubyte)(a % ubyte.max)))
1294 			ubytes.insert(i);
1295 		assert(ubytes[].walkLength == 500_000, "%d".format(ubytes[].walkLength));
1296 		assert(ubytes.length == 500_000, "%d".format(ubytes.length));
1297 		foreach (i; iota(0, 1_000_000).filter!(a => a % 2 == 0).map!(a => cast(ubyte)(a % ubyte.max)))
1298 			assert(!ubytes.equalRange(i).empty);
1299 	}
1300 
1301 	{
1302 		import std.experimental.allocator.building_blocks.free_list : FreeList;
1303 		import std.experimental.allocator.building_blocks.allocator_list : AllocatorList;
1304 		import std.experimental.allocator.building_blocks.region : Region;
1305 		import std.experimental.allocator.building_blocks.stats_collector : StatsCollector;
1306 		import std.stdio : stdout;
1307 
1308 		StatsCollector!(FreeList!(AllocatorList!(a => Region!(Mallocator)(1024 * 1024)),
1309 			64)) allocator;
1310 		{
1311 			auto ints4 = TTree!(int, typeof(&allocator))(&allocator);
1312 			foreach (i; 0 .. 10_000)
1313 				ints4.insert(i);
1314 			assert(walkLength(ints4[]) == 10_000);
1315 		}
1316 		assert(allocator.numAllocate == allocator.numDeallocate);
1317 		assert(allocator.bytesUsed == 0);
1318 	}
1319 }
1320 
1321 version(emsi_containers_unittest) unittest
1322 {
1323 	static class Foo
1324 	{
1325 		string name;
1326 
1327 		this(string s)
1328 		{
1329 			this.name = s;
1330 		}
1331 	}
1332 
1333 	TTree!(Foo, Mallocator, false, "a.name < b.name") tt;
1334 	auto f = new Foo("foo");
1335 	tt.insert(f);
1336 	f = new Foo("bar");
1337 	tt.insert(f);
1338 	auto r = tt[];
1339 }
1340 
1341 version(emsi_containers_unittest) unittest
1342 {
1343 	import std.range : walkLength;
1344 	import std.stdio;
1345 
1346 	TTree!(int, Mallocator, true) tt;
1347 	tt.insert(10);
1348 	tt.insert(11);
1349 	tt.insert(12);
1350 	assert(tt.length == 3);
1351 	tt.insert(11);
1352 	assert(tt.length == 4);
1353 	tt.remove(11);
1354 	assert(tt.length == 3);
1355 	assert(tt[].walkLength == tt.length);
1356 }